(function() {
	module('Tic Tac Toe Tests');

	var X = Player.X;
	var O = Player.O;
	var _ = null;

	test('Setup OK', function() {
		ok(true);
	});

	test('Startup', function() {
		var view = new TestView();
		var controller = new TicTacToeController(view);

		controller.startup();

		ok(view.controller === controller);
	});

	test('Player move first', function() {
		var view = new TestView();
		var controller = new TicTacToeController(view);

		controller.startup();
		controller.move(1, 1);

		deepEqual(Player.O, view.board.squareAt(1, 1).player());
	});

	test('Computer must play after Player\'s move', function() {
		var view = new TestView();
		var controller = new TicTacToeController(view);

		controller.startup();
		controller.move(1, 1);

		function checkComputerMoved() {
			var squares = view.board.state();
			var moveCount = 0;
			for (var i = 0; i < squares.length; i++) {
				var square = squares[i];

				if (square === Player.X) {
					moveCount++;
				}
			}

			return moveCount === 1;
		}

		ok(checkComputerMoved());
	});

	test('Not allowed move', function() {
		var view = new TestView();
		var controller = new TicTacToeController(view);

		var boardConfig = [//
		_, X, _,//
		_, O, _, //
		_, _, _];
		controller._setBoard(boardConfig);
		controller.startup();

		controller.move(0, 1);

		deepEqual(view.board.state(), boardConfig);
	});

	test('Stale', function() {
		var view = new TestView();
		var controller = new TicTacToeController(view);

		var boardConfig = [//
		O, X, O,//
		X, O, O, //
		X, _, X];
		controller._setBoard(boardConfig);
		controller.startup();

		controller.move(2, 1);

		ok(view.stale === true);
	});

	test('Player wins on col', function() {
		var view = new TestView();
		var controller = new TicTacToeController(view);

		var boardConfig = [//
		X, _, _,//
		X, O, O, //
		_, X, O];
		controller._setBoard(boardConfig);
		controller.startup();

		controller.move(0, 2);

		equal(view.winner, Player.O);
	});

	test('Player wins on row', function() {
		var view = new TestView();
		var controller = new TicTacToeController(view);

		var boardConfig = [//
		X, X, _,//
		_, O, O, //
		_, X, O];
		controller._setBoard(boardConfig);
		controller.startup();

		controller.move(1, 0);

		equal(view.winner, Player.O);
	});

	test('Player wins on LR row', function() {
		var view = new TestView();
		var controller = new TicTacToeController(view);

		var boardConfig = [//
		O, X, X,//
		_, O, O, //
		_, X, _];
		controller._setBoard(boardConfig);
		controller.startup();

		controller.move(2, 2);

		equal(view.winner, Player.O);
	});

	test('Player wins on RL row', function() {
		var view = new TestView();
		var controller = new TicTacToeController(view);

		var boardConfig = [//
		_, X, O,//
		_, O, _, //
		_, X, _];
		controller._setBoard(boardConfig);
		controller.startup();

		controller.move(2, 0);

		equal(view.winner, Player.O);
	});

	test('Computer wins on RL row', function() {
		var view = new TestView();
		var controller = new TicTacToeController(view);

		var boardConfig = [//
		X, O, _,//
		_, X, _, //
		_, O, _];
		controller._setBoard(boardConfig);
		controller.startup();
		controller._currentAI = new function() {
			this.nextMove = function() {
				return {
					row : 2,
					col : 2
				};
			};
		};

		controller.move(1, 0);

		equal(view.winner, Player.X);
	});

	test('Solution', function() {
		var view = new TestView();
		var controller = new TicTacToeController(view);
		controller._handleRoundOver = function() {
			controller._nextStep();
		};

		controller.startup();

		function DiagonalMovingAI() {
			var index = -1;
			this.nextMove = function() {
				index++;
				return {
					row : index,
					col : index
				};
			};
		}

		// We will play this round 3 times, to solve the puzzle
		// X_O XOO XOO
		// ___ _X_ _XO
		// __X ___ __X
		for (var round = 0; round < 3; round++) {
			controller._currentAI = new DiagonalMovingAI();
			view.winner = null;

			controller.move(0, 2);
			controller.move(0, 1);
			controller.move(1, 2);

			equal(view.winner, Player.X);
		}
		ok(view.solved);

	});

	function TestView() {
	}

	TestView.prototype.init = function(controller) {
		this.controller = controller;
	};

	TestView.prototype.update = function(board) {
		this.board = board;
	};

	TestView.prototype.updateScore = function(match) {
	};

	TestView.prototype.onReset = function() {
		this.onResetCalled = true;
	};

	TestView.prototype.onSolved = function() {
		this.solved = true;
	};

	TestView.prototype.onStale = function() {
		this.stale = true;
	};

	TestView.prototype.onWinner = function(winner) {
		this.winner = winner;
	};

}());

(function() {
	module('Heuristic Tests');
	var X = Player.X;
	var O = Player.O;
	var _ = null;

	test('+1 for EACH 1-in-a-line (with two empty cells) for computer', function() {
		var board = new TBoard([//
		X, _, _,//
		_, _, _,//
		_, _, _]);

		var evaluation = new Heuristic(board, Player.X).evaluate();

		equal(evaluation, +1);
	});

}());